#include "fxcc/core/graph/common/Scene.h"
#include "fxcc/core/graph/common/GraphImpl.h"

using namespace fxcc::graph::common;

Scene::Scene(const std::string &path)
    : m_Name(fs::path(path).filename().string())
{
    m_Path = fxcc::Base::normalizePath(path);

    m_Enabled = Create(path);
};

bool Scene::Create(const std::string &path)
{
    Assimp::Importer importer;

    importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);

    const aiScene *scene = importer.ReadFile(
        path,
        aiProcess_GenSmoothNormals |
        aiProcess_FlipUVs |
        aiProcess_CalcTangentSpace |
        aiProcess_GenBoundingBoxes |
        aiProcess_Triangulate |
        aiProcess_ImproveCacheLocality |
        aiProcess_SortByPType
        // | aiProcess_PopulateArmatureData
    );
    ztclog::info("try load scene %s", m_Path.c_str());

    if (!IsAvailed(scene))
    {
        ztclog::info("cannot load model %s", path.c_str());
        return false;
    }
    bool res = Create(scene, path);
    importer.FreeScene();

    return res;
}

void fxcc::graph::common::Scene::ProcessNode(fxcc::graph::common::Node* node)
{

    for (int i = 0; i < m_Cameras.size(); i++)
    {
        if (node->m_Name == m_Cameras[i]->m_Name)
        {
            node->m_Cameras.push_back(i);
        }
    }
    for (int i = 0; i < m_LightDatas.size(); i++)
    {
        if (node->m_Name == m_LightDatas[i]->m_Name)
        {
            node->m_Lights.push_back(i);
        }
    }

    for (auto childNode : node->m_Childern)
    {
        ProcessNode(childNode.get());
    }
}

bool Scene::Create(const aiScene* scene, const std::string& path)
{
    m_RootNode = std::make_shared<Node>(scene->mRootNode);

    for (int i = 0; i < scene->mNumMeshes; i++)
    {
        auto newMesh = std::make_shared<MeshData>(scene->mMeshes[i]);
        m_MeshDatas.push_back(newMesh);

    };

    for (int i = 0; i < scene->mNumAnimations; i++)
    {
        m_Animations.push_back(std::make_shared<Animation>(scene->mAnimations[i]));
    }
    for (int i = 0; i < scene->mNumCameras; i++)
    {
        m_Cameras.push_back(std::make_shared<CameraData>(scene->mCameras[i]));
    }
    for (int i = 0; i < scene->mNumLights; i++)
    {
        m_LightDatas.push_back(std::make_shared<LightData>(scene->mLights[i]));
    }

    std::string parentPath = fs::path(path).parent_path().string();

    for (int i = 0; i < scene->mNumMaterials; i++)
    {
        auto inst = std::make_shared<MaterialData>(scene->mMaterials[i], parentPath);
        
        if (inst->m_Name.empty())
        {
            inst->m_Name = m_Name + std::to_string(i);
        }
        m_Materials.push_back(inst);
    }
    ProcessNode(m_RootNode.get());

 
    return true;
};

void Scene::CalAABB(const AABB& other)
{
    //auto& sceneMin = this->m_AABB.m_Min;
    //auto& sceneMax = this->m_AABB.m_Max;

    //const auto& meshMin = other.m_Min;
    //const auto& meshMax = other.m_Max;

    //sceneMin.x = std::min(sceneMin.x, meshMin.x);
    //sceneMin.y = std::min(sceneMin.y, meshMin.y);
    //sceneMin.z = std::min(sceneMin.z, meshMin.z);

    //sceneMax.x = std::max(sceneMax.x, meshMax.x);
    //sceneMax.y = std::max(sceneMax.y, meshMax.y);
    //sceneMax.z = std::max(sceneMax.z, meshMax.z);

    //m_AABB.CalCenterHalfExt();
}

bool fxcc::graph::common::Scene::IsAvailed(const aiScene* scene)
{
    if (scene == 0)
    {
        return false;
    }
    if (scene->mRootNode==0)
    {
        return false;
    }
    return true;
}
